package com.ruoyi.boat.ws;


import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;


/**
 * 原文链接：https://blog.csdn.net/qq_48721706/article/details/124995148
 */
@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocket {

    // 与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private String userId;
    private String boatCodes;

    // concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    // 虽然@Component默认是单例模式的，但springboot还是会为每个websocket连接初始化一个bean，所以可以用一个静态set保存起来。
    // 底下WebSocket是当前类名
    private static final CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();

    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        try {
            this.session = session;
            webSockets.add(this);
            this.userId = userId;
            log.info("【websocket消息】有新的连接，总数为: {}, userId: {}", webSockets.size(), userId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            log.info("【websocket消息】连接断开，总数为:" + webSockets.size());
        } catch (Exception e) {
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("【websocket消息】收到客户端{} 消息: {}", userId, message);
        String[] split = message.split(":");
        if (split.length < 2) return;
        String type = split[0];
        String value = split[1];

        if (type.equals("codes")) {
            this.boatCodes = value;
        }
    }

    /**
     * 发送错误时的处理
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户{}错误, 原因: {}", userId, error.getMessage());
        error.printStackTrace();
    }

    private void send(Session session, String message) {
        try {
            if (session.isOpen()) {
                session.getAsyncRemote().sendText(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 全体发送
     *
     * @param message
     */
    public void sendAll(String message) {
        for (WebSocket webSocket : webSockets) {
            send(webSocket.session, message);
        }
    }

    /**
     * 单点发送
     *
     * @param userId
     * @param message
     */
    public void sendOne(String userId, String message) {
        for (WebSocket webSocket : webSockets) {
            if (!webSocket.userId.equals(userId)) continue;
            send(webSocket.session, message);
        }
    }

    /**
     * 多人发送
     *
     * @param userIds
     * @param message
     */
    public void sendMore(List<String> userIds, String message) {
        for (WebSocket webSocket : webSockets) {
            if (!userIds.contains(webSocket.userId)) continue;
            send(webSocket.session, message);
        }
    }

    /**
     * 按艇编号发送
     *
     * @param boatCode
     * @param message
     */
    public void sendByBoatCode(String boatCode, String message) {
        for (WebSocket webSocket : webSockets) {
            if (!webSocket.boatCodes.contains(boatCode)) continue;
            send(webSocket.session, message);
        }
    }

}
